﻿
Imports System.IO
Imports std
Imports monitorlock = lock(Of locks.monitorlock)
Imports IOP = System.IO.Path

Namespace storageJobConsumerInternal
    Namespace diskslice
        Public Module _diskslice
            Public Const diskOperDefaultBuffSize As Int32 = 131072
            Public ReadOnly diskOperDefaultHoldtimeMs As Int32 = secondsToMilliseconds(30)
            Private ReadOnly pc As map(Of String, Int32) = Nothing
            Private ReadOnly dc As map(Of String, Int32) = Nothing
            Private ReadOnly dd As map(Of String, DriveInfo) = Nothing
            Private l As monitorlock
            Private locked As Boolean = False

            Sub New()
                pc = New map(Of String, Int32)()
                dc = New map(Of String, Int32)()
                dd = New map(Of String, DriveInfo)()
            End Sub

            Private Sub lock()
                l.wait()
            End Sub

            Private Sub unlock()
                l.release()
            End Sub

            Private Function pathRoot(ByVal path As String) As String
                assert(IOP.IsPathRooted(path))
                Return IOP.GetPathRoot(path).TrimEnd(filesystem.pathSeperator)
            End Function

            Public Function increment(ByVal path As String) As Int32
                assert(Not locked)
                assert(IOP.IsPathRooted(path), "path ", path, " is not rooted.")
                Dim rtn As Int32 = 0
                lock()
                pc(path) += 1
                rtn = pc(path)
                Dim root As String = pathRoot(path)
                dc(root) += 1
                dd(root) = New DriveInfo(root)
                unlock()
                Return rtn
            End Function

            Private Function read(ByVal m As map(Of String, Int32), ByVal s As String) As Int32
                locked = True
                assert(Not m Is Nothing)
                assert(Not isemptystring(s))
                Dim rtn As Int32 = 0
                rtn = m(s)
                assert(rtn > 0)
                Return rtn
            End Function

            Public Function sharePathDisksliceCount(ByVal path As String) As Int32
                assert(IOP.IsPathRooted(path))
                Return read(pc, path)
            End Function

            Public Function shareDriveDisksliceCount(ByVal path As String) As Int32
                Return read(dc, pathRoot(path))
            End Function

            Public Function driveFreeSpace(ByVal path As String) As Int64
                locked = True
                Dim di As DriveInfo = Nothing
                di = dd(pathRoot(path))
                assert(Not di Is Nothing)
                Return di.AvailableFreeSpace()
            End Function
        End Module
    End Namespace

    Partial Public MustInherit Class diskslice(Of ATOM_T As atom)
        Private Shared Function initialIndexfile(ByVal name As String,
                                                 ByVal config As configParser,
                                                 ByVal s As diskslice(Of ATOM_T)) As Boolean
            Dim path As String = Nothing
            path = config.parameter(name,
                                    "datapath",
                                    combinepath(filesystem.deployRoot, "data", envs.serviceName(), name))
            path = Global.fullpath(path)
            Directory.CreateDirectory(path)
            Dim index As Int32 = 0
            index = diskslice.increment(path)
            s.datafullpath() = path
            s.indexfile() = Convert.ToString(index)
            s.indexfilefullpath() = combinepath(path, s.indexfile())
            Return True
        End Function

        Private Shared Function initialMemoryBuffSize(ByVal name As String,
                                                      ByVal config As configParser,
                                                      ByVal s As diskslice(Of ATOM_T)) As Boolean
            Const defaultValue As String = "auto"
            Dim memoryBuffSize As Int32 = 0
            Dim str As String = Nothing
            If config.getparameter(name, "memoryBuffSize", str, defaultValue) AndAlso
               strsame(str, defaultValue, False) Then
                memoryBuffSize = (availablePhysicalMemory() >> 14)
                'for 2G memory, use 131072 bytes as buffer, so can contain about 16384 slices
            ElseIf Not convertor.toint32(str, memoryBuffSize) Then
                memoryBuffSize = DEFAULT_STREAM_BUFFER
            ElseIf memoryBuffSize <= NO_STREAM_BUFFER Then
                memoryBuffSize = NO_STREAM_BUFFER
            End If
            s.memoryBuffSize() = memoryBuffSize
            Return True
        End Function

        Private Shared Function initialMaxAtomsCount(ByVal name As String,
                                                     ByVal config As configParser,
                                                     ByVal s As diskslice(Of ATOM_T)) As Boolean
            Const defaultValue As UInt64 = (1 << 13)    '8192
            Dim maxAtomsCount As UInt64 = 0
            Dim str As String = Nothing
            If Not config.getparameter(name, "maxAtomsCount", str, defaultValue.ToString()) OrElse
               Not convertor.touint64(str, maxAtomsCount) OrElse
               maxAtomsCount = 0 Then
                maxAtomsCount = defaultValue
            End If
            s.maxAtomsCount() = maxAtomsCount
            Return True
        End Function

        Private Shared Function initialMaxIndexSize(ByVal name As String,
                                                    ByVal config As configParser,
                                                    ByVal s As diskslice(Of ATOM_T)) As Boolean
            Const defaultValue As UInt64 = (1 << 27)    '134217728
            Dim maxIndexSize As UInt64 = 0
            Dim str As String = Nothing
            If Not config.getparameter(name, "maxIndexSize", str, defaultValue.ToString()) OrElse
               Not convertor.touint64(str, maxIndexSize) OrElse
               maxIndexSize = 0 Then
                maxIndexSize = defaultValue
            End If
            s.maxIndexSize() = maxIndexSize
            Return True
        End Function

        Private Shared Function initialPreservedDriveSpace(ByVal name As String,
                                                           ByVal config As configParser,
                                                           ByVal s As diskslice(Of ATOM_T)) As Boolean
            Const defaultValue As UInt64 = (1 << 27)    '134217728
            Dim preservedDriveSpace As UInt64 = 0
            Dim str As String = Nothing
            If Not config.getparameter(name, "preservedDriveSpace", str, defaultValue.ToString()) OrElse
               Not convertor.touint64(str, preservedDriveSpace) OrElse
               preservedDriveSpace = 0 Then
                preservedDriveSpace = defaultValue
            End If
            s.preservedDriveSpace() = preservedDriveSpace
            Return True
        End Function

        Private Delegate Function initializer(ByVal name As String,
                                              ByVal config As configParser,
                                              ByVal s As diskslice(Of ATOM_T)) As Boolean
        Private Shared ReadOnly initializers() As initializer = Nothing

        Private Shared Function create_initializers() As initializer()
            Return New initializer() {AddressOf initialIndexfile,
                                      AddressOf initialMemoryBuffSize,
                                      AddressOf initialMaxAtomsCount,
                                      AddressOf initialMaxIndexSize,
                                      AddressOf initialPreservedDriveSpace}
        End Function

        Protected Shared Shadows Function initial(ByVal name As String,
                                                  ByVal config As configParser,
                                                  ByVal s As diskslice(Of ATOM_T)) _
                                                 As Boolean
            assert(Not isemptystring(name))
            assert(Not config Is Nothing)
            assert(Not s Is Nothing)
            For i As Int32 = 0 To initializers.Length() - 1
                If Not initializers(i)(name, config, s) Then
                    Return False
                End If
            Next
            Return s.open() OrElse s.create_open()
        End Function
    End Class
End Namespace
